package pgui;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JPanel;
import javax.swing.Timer;

import pgui.visual.PComponent;

/**
 * 
 * @author Pedro Silva Moreira
 */
public class PVisual extends JPanel implements ActionListener {
	private static final long serialVersionUID = 1L;

	// Local Variables
	private Timer timer;
	private PComponent mainComponent, focusedComponent, mouseComponent = null;
	private Boolean clip = false;
	private MouseEvent lastMoveEvent;

	// Creation
	public PVisual(int fps) {
		super();
		timer = new Timer(1000 / fps, this);
		timer.start();

		this.setFocusable(true);
		this.requestFocus();
		this.setMainComponent(new PComponent(this));

		// Mouse Events
		this.addMouseListener(new MouseListener() {

			@Override
			public void mouseReleased(MouseEvent event) {
				if(getMouseComponent() != null)
					getMouseComponent().onMouseReleased(event);
				else getMainComponent().onMouseReleased(event);
			}

			@Override
			public void mousePressed(MouseEvent event) {
				if(getMouseComponent() != null)
					getMouseComponent().onMousePressed(event);
				else getMainComponent().onMousePressed(event);
			}

			@Override
			public void mouseExited(MouseEvent event) {
				// getMainComponent().onMouseExited(event);
			}

			@Override
			public void mouseEntered(MouseEvent event) {
				// getMainComponent().onMouseEntered(event);
			}

			@Override
			public void mouseClicked(MouseEvent event) {
				if(getMouseComponent() != null)
					getMouseComponent().onMouseClicked(event);
				else getMainComponent().onMouseClicked(event);
			}
		});

		this.addMouseMotionListener(new MouseMotionListener() {

			@Override
			public void mouseMoved(MouseEvent event) {
				if(getMouseComponent() != null)
					getMouseComponent().onMouseMoved(event, getLastMoveEvent());
				else getMainComponent().onMouseMoved(event, getLastMoveEvent());
				setLastMoveEvent(event);
			}

			@Override
			public void mouseDragged(MouseEvent event) {
				if(getMouseComponent() != null)
					getMouseComponent().onMouseDragged(event, getLastMoveEvent());
				else getMainComponent().onMouseDragged(event, getLastMoveEvent());
				setLastMoveEvent(event);
			}
		});

		// Keyboard Events
		this.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent event) {
				if (getFocusedComponent() == null)
					return;

				getFocusedComponent().onKeyTyped(event);
			}

			@Override
			public void keyReleased(KeyEvent event) {
				if (getFocusedComponent() == null)
					return;

				getFocusedComponent().onKeyReleased(event);
			}

			@Override
			public void keyPressed(KeyEvent event) {
				if (getFocusedComponent() == null)
					return;

				getFocusedComponent().onKeyPressed(event);
			}
		});
	}

	// Paint
	@Override
	public void actionPerformed(ActionEvent e) {
		this.repaint();
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		this.onPaint((Graphics2D) g);
	}

	// Size
	public void maxSize() {
		this.setSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
		this.setPreferredSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
	}

	// Event
	public void onPaint(Graphics2D g) {
		if (this.getMainComponent() == null)
			return;

		getMainComponent().setParentLastX(this.getX());
		getMainComponent().setParentLastY(this.getY());
		getMainComponent().onPaint(g);
		getMainComponent().onPaintChild(g);
	}

	// Get & Set
	public PComponent getMainComponent() {
		return mainComponent;
	}

	public void setMainComponent(PComponent mainComponent) {
		this.mainComponent = mainComponent;
		this.mainComponent.setVisual(this);
		this.mainComponent.setRelativeWidth(100);
		this.mainComponent.setRelativeHeight(100);
		this.setFocusedComponent(this.getMainComponent());
	}

	public PComponent getFocusedComponent() {
		return focusedComponent;
	}

	public void setFocusedComponent(PComponent focusedComponent) {
		this.focusedComponent = focusedComponent;
	}

	public Boolean getClip() {
		return clip;
	}

	public void setClip(Boolean clip) {
		this.clip = clip;
	}

	public MouseEvent getLastMoveEvent() {
		return lastMoveEvent;
	}

	public void setLastMoveEvent(MouseEvent lastMoveEvent) {
		this.lastMoveEvent = lastMoveEvent;
	}

	public PComponent getMouseComponent() {
		return mouseComponent;
	}

	public void setMouseComponent(PComponent mouseComponent) {
		this.mouseComponent = mouseComponent;
	}
}
